package utils

import (
	"net"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/idna"

	"github.com/cloudwego/kitex/pkg/klog"
)

func ValidateDomain(domain string) bool {
	if len(domain) == 0 || len(domain) > 256 {
		return false
	}

	labels := strings.Split(domain, ".")
	if len(labels) < 2 {
		return false
	}
	re, err := regexp.Compile(`^[a-zA-Z0-9-]+$`) // nolint
	if err != nil {
		klog.Errorf("ValidateDomain: %v", err)
		return false
	}
	for _, label := range labels {
		if len(label) > 63 {
			return false
		}
		labelBytes := []byte(label)
		if labelBytes[0] == '-' || labelBytes[len(labelBytes)-1] == '-' {
			return false
		}
		if !re.MatchString(label) {
			return false
		}
	}

	return true
}

func ValidatePublicIP(ipText string) bool {
	ip := net.ParseIP(ipText)
	return ip.IsGlobalUnicast() && !ip.IsPrivate()
}

func ValidateCIDR(ipText string) bool {
	_, _, err := net.ParseCIDR(ipText)
	return err == nil
}

func ValidatePublicIPv4(ipText string) bool {
	ip := net.ParseIP(ipText).To4()
	return ip.IsGlobalUnicast() && !ip.IsPrivate()
}

func ValidatePublicIPv6(ipText string) bool {
	ip := net.ParseIP(ipText).To16()
	return ip.IsGlobalUnicast() && !ip.IsPrivate()
}

func ValidatePort(portText string) bool {
	port, err := strconv.Atoi(portText)
	if err != nil || port <= 0 || port > 65535 {
		return false
	}

	return true
}

// ValidFqdn 是否合法的完全限定域名
func ValidFqdn(portText string) bool {
	// TODO
	return true
}

func PunycodeEncode(domain string) (encodedDomain string, err error) {
	// Punycode 编码
	encodedDomain, err = idna.ToASCII(domain)
	if err != nil {
		klog.Errorf("PunycodeEncode err: %+v, domain: %v, encodedDomain:%v", err, domain, encodedDomain)
	}
	return encodedDomain, err
}

func PunycodeDecode(domain string) (decodedDomain string, err error) {
	// Punycode 解码
	decodedDomain, err = idna.ToUnicode(domain)
	if err != nil {
		klog.Errorf("Punycode encoding error: %v, domain: %v, decodedDomain: %+v", err, domain, decodedDomain)
	}
	return decodedDomain, err
}
